/**
  ETFAna project, Anyang Normal University && IMP-CAS
  \class ETFMsg
  \brief to print runtime message
  \author SUN Yazhou, asia.rabbit@163.com
  \since 2021-10-03
  \date 2021-10-03 last modified
  \attention
  changelog
  <table>
  <tr>  <th>Date         <th>Author      <th>Description                   </tr>
  <tr>  <td>2021-10-03   <td>Asia Sun    <td>file created                  </tr>
  </table>

  \copyright Copyright (c) 2021-2024 Anyang Normal U. && IMP-CAS with LGPLv3 LICENSE
*/

#include <ctime>
#include <stdarg.h> // variable arguments handle function declarations
#include <cstdlib>
#include <chrono>
#include <signal.h> // for kill
#include <unistd.h> // for getpid
#include <errno.h> // for errno
#include <cstring> // for strerror

#include "ETFMsg.h"

using std::cout;
using std::endl;

// assignment and definition
char ETFMsg::fMsg[512];
bool ETFMsg::fIsVerbose = false;
bool ETFMsg::fIsSilent = false;
bool ETFMsg::fIsDebug = true;
bool ETFMsg::fIsInterrupted = false;

ETFMsg::ETFMsg(){}
ETFMsg::~ETFMsg(){}

// just like sprintf
const char *ETFMsg::Form(const char *fmt, ...){
	strcpy(fMsg, "");
	va_list arg_ptr;
	va_start(arg_ptr, fmt);
	vsprintf(fMsg, fmt, arg_ptr);
	va_end(arg_ptr);
	return fMsg;
} // end member function Form

void ETFMsg::Info(const char *cname, const char *fmt, ...){
	if(fIsSilent) return;

	char msg[1024], omsg[1024];
	va_list arg_ptr;
	va_start(arg_ptr, fmt);
	sprintf(msg, "  ETFAna-Info: \033[32;1m[%s]\033[34;1m %s\n\033[0m", cname, fmt);
	vsprintf(omsg, msg, arg_ptr);
	va_end(arg_ptr);
	cout << omsg;
} // end member function Info

void ETFMsg::Error(const char *cname, const char *fmt, ...){
	static bool nomore = false;
	if(nomore) return;

	char msg[1024], omsg[1024];
	va_list arg_ptr;
	va_start(arg_ptr, fmt);
	sprintf(msg, "\033[31;1m  ETFAna-Error: \033[0m\033[33;1m[%s]\033[0m\033[31;1m %s\n\033[0m", cname, fmt);
	vsprintf(omsg, msg, arg_ptr);
	va_end(arg_ptr);
	cout << omsg;

	// exit(1);
	// select repeatability
	if(!nomore){
		cout << "[q]: abort, [n]: do not stop any more, others: continue > " << std::flush;
		string str;
		std::getline(std::cin, str);
		if(!str.empty() && (str.c_str())[0] == 'q'){
			cout << "Aborting ETF...\n";
			exit(1);
		}
		else if(!str.empty() && (str.c_str())[0] == 'n'){
			nomore = true;
		}
		cout << std::endl;
	}
} // end member function Error

void ETFMsg::Warn(const char *cname, const char *fmt, ...){
	static bool nomore = false;
	if(nomore) return;

	char msg[1024], omsg[1024];
	va_list arg_ptr;
	va_start(arg_ptr, fmt);
	sprintf(msg, "\033[36;1m  ETFAna-Warning: \033[0m\033[33;1m[%s]\033[0m\033[36;1m %s\n\033[0m", cname, fmt);
	vsprintf(omsg, msg, arg_ptr);
	va_end(arg_ptr);
	cout << omsg;

	// // select repeatability
	// if(!nomore){
	// 	cout << "[q]: abort, [n]: do not stop any more, others: continue > " << std::flush;
	// 	string str;
	// 	std::getline(std::cin, str);
	// 	if(!str.empty() && (str.c_str())[0] == 'q'){
	// 		cout << "Aborting ETF...\n";
	// 		exit(1);
	// 	}
	// 	else if(!str.empty() && (str.c_str())[0] == 'n'){
	// 		nomore = true;
	// 	}
	// 	cout << std::endl;
	// } // end if
} // end member function Warn

void ETFMsg::Debug(const char *cname, const char *fmt, ...){
	if(!fIsDebug) return;

	char msg[1024], omsg[1024];
	va_list arg_ptr;
	va_start(arg_ptr, fmt);
	sprintf(msg, "  ETFAna-Debug: \033[33;1m[%s]\033[0m %s\n", cname, fmt);
	vsprintf(omsg, msg, arg_ptr);
	va_end(arg_ptr);
	cout << omsg;

	cout << "Press ENTER to continue...";
	getchar();
} // end member function Debug

void ETFMsg::ConfigInfo(const char *cname, const char *fmt, ...){
	if(!fIsVerbose) return;

	char msg[1024], omsg[1024];
	va_list arg_ptr;
	va_start(arg_ptr, fmt);
	sprintf(msg, "\033[32;1m  ETFAna-ConfigInfo: \033[0m\033[33;1m[%s]\033[0m\033[32;1m %s\n\033[0m", cname, fmt);
	vsprintf(omsg, msg, arg_ptr);
	va_end(arg_ptr);
	cout << omsg;
} // end member function ConfigInfo

void ETFMsg::ShowPoint(const char *msg, const double *p, const int len){
	for(int i = 0; i < len; i++)
		cout << msg << "[" << i << "]: " << p[i] << "\t";
} // end member function ShowPoint

// isName: no comma in the returned string, suitable for path and file name
const char *ETFMsg::time0(bool isName){
	time_t tt = ::time(NULL);
	tm *t = localtime(&tt);
	static char ttt[128];
	if(!isName) sprintf(ttt, "%d-%02d-%02d_%02d:%02d", t->tm_year + 1900,
	 t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min);
	else sprintf(ttt, "%d%02d%02d_%02d%02d", t->tm_year + 1900,
	 t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min);
	return ttt;
} // end member function time0

// isName: no comma in the returned string, suitable for path and file name
const char *ETFMsg::sec0(bool isName){
	time_t tt = ::time(NULL);
	tm *t = localtime(&tt);
	static char ttt[128];
	if(!isName) sprintf(ttt, "%d-%02d-%02d_%02d:%02d:%02d", t->tm_year + 1900,
	 t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
	else sprintf(ttt, "%d%02d%02d_%02d%02d%02d", t->tm_year + 1900,
	 t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
	return ttt;
} // end member function sec0

void ETFMsg::LogoPlain(string &s){
	s += "\n";
	// s += " -----------------------------------------------------------\n";
	// s += " |   EEEEEEE  TTTTTTT  FFFFFF     A                        |\n";
	// s += " |   E           T     F         A A                       |\n";
	// s += " |   EEEEE       T     FFFF     A   A    n n n   a a a     |\n";
	// s += " |   E           T     F       A  A  A   n   n   a   a     |\n";
	// s += " |   EEEEEE X    T     F      A       A  n   n   a a a a   |\n";
	// s += " -----------------------------------------------------------\n";
	s += "------------------------ ETFAna Project ----------------------\n";
	s += "----------------- Version 3.1.0 July 12, 2024 ----------------\n";
	s += "------------ https://gitee.com/asiarabbit/etfana -----------\n";
	s +=       "______Author: SUN Yazhou, asia.rabbit@163.com______\n";
	s += '\n';
} // end member function LogoPlain

void ETFMsg::Logo(std::ostream &os){
	os << "\033[32;1m\n";
	os << " -----------------------------------------------------------" << endl;
	os << " |   EEEEEEE  TTTTTTT  FFFFFF     A                        |" << endl;
	os << " |   E           T     F         A A                       |" << endl;
	os << " |   EEEEE       T     FFFF     A   A    n n n   a a a     |" << endl;
	os << " |   E           T     F       A  A  A   n   n   a   a     |" << endl;
	os << " |   EEEEEE \033[31;1mX\033[32;1m    T     F      A       A  n   n   a a a a   |" << endl;
	os << " -----------------------------------------------------------" << endl;
	os << "\033[0m";
	os << "------------------------ ETFAna Project ----------------------" << endl;
	os << "----------------- Version 3.1.0 July 12, 2024 ----------------" << endl;
	os << "------------- https://gitee.com/asiarabbit/etfana ------------" << endl;
	os << "____________Author: SUN Yazhou, asia.rabbit@163.com___________" << endl;
} // end member function Logo

// a clock in ms()
time_t ETFMsg::ms(){
	return std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
} // end member function ms

// time w.r.t the program execution time
time_t ETFMsg::ms1(){
	static const time_t tt0 = ms();
	return ms() - tt0;
} // end member function ms1

void ETFMsg::SetInterrupted(){
	fIsInterrupted = true;
} // end member function SetInterrupted
